Passed
Push — development ( 26403f...98b3d9 )
by Vad
08:03 queued 49s
created

BicyclesService.findByLocation   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 5
dl 0
loc 6
ccs 0
cts 4
cp 0
crap 2
rs 10
c 0
b 0
f 0
1 11
import { Injectable } from '@nestjs/common';
2 11
import { InjectRepository } from '@nestjs/typeorm';
3 11
import { Repository } from 'typeorm';
4 11
import { Bicycle } from './entities/bicycle.entity';
5 11
import { NotFoundException } from '@nestjs/common';
0 ignored issues
show
introduced by
'@nestjs/common' import is duplicated.
Loading history...
6
import { UpdateBicycleDto } from './dto/update-bicycle.dto';
7
import { BicycleResponse } from './types/bicycle-response.interface';
8 11
import { getDistance } from 'src/utils/geo.utils';
9
import { CreateBicycleDto } from './dto/create-bicycle.dto';
10 11
import { City } from 'src/cities/entities/city.entity';
11 11
import { CityName } from 'src/cities/types/city.enum';
12
13
@Injectable()
14 11
export class BicyclesService {
15
  constructor(
16
    @InjectRepository(Bicycle)
17 5
    private readonly bicycleRepository: Repository<Bicycle>,
18
    @InjectRepository(City)
19 5
    private cityRepository: Repository<City>,
20
  ) {}
21
22
  async findAll(): Promise<Bicycle[]> {
23
    const bikes = await this.bicycleRepository.find({
24
      relations: {
25
        city: true,
26
      },
27
      select: {
28
        id: true,
29
        batteryLevel: true,
30
        latitude: true,
31
        longitude: true,
32
        status: true,
33
        createdAt: true,
34
        updatedAt: true,
35
        city: {
36
          name: true,
37
        },
38
      },
39
    });
40
41
    return bikes;
42
  }
43
44
  async setRented(bikeId: string): Promise<Bicycle> {
45 2
    const result = await this.bicycleRepository.update(
46
      { id: bikeId, status: 'Available' },
47
      { status: 'Rented' },
48
    );
49 2
    if (result.affected === 0) {
50 1
      throw new NotFoundException(
51
        "Bike couldn't be rented. Bike might not exist or it is not available.",
52
      );
53
    }
54 1
    return await this.findById(bikeId);
55
  }
56
57
  async createBike(createBicycleDto: CreateBicycleDto): Promise<Bicycle> {
58
    const bike = this.bicycleRepository.create({
59
      batteryLevel: createBicycleDto.batteryLevel ?? 100,
60
      latitude: createBicycleDto.latitude,
61
      longitude: createBicycleDto.longitude,
62
      status: createBicycleDto.status ?? 'Available',
63
    });
64
65 2
    const city = createBicycleDto.city ?? 'Göteborg';
66
    // Find the city by name
67
    const cityEntity = await this.cityRepository.findOne({
68
      where: { name: city as CityName },
69
    });
70
71 1
    if (cityEntity) {
72
      bike.city = cityEntity;
73
    }
74
75
    return await this.bicycleRepository.save(bike);
76
  }
77
78
  async createManyBikes(createBicycleDto: CreateBicycleDto[]): Promise<Bicycle[]> {
79
    const defaultCity = await this.cityRepository.findOne({
80
      where: { name: CityName.Göteborg }
0 ignored issues
show
introduced by
Insert ,
Loading history...
81
    });
82
    const Karlshamn = await this.cityRepository.findOne({
83
      where: { name: CityName.Karlshamn }
0 ignored issues
show
introduced by
Insert ,
Loading history...
84
    });
85
    const Jönköping = await this.cityRepository.findOne({
86
      where: { name: CityName.Jönköping }
0 ignored issues
show
introduced by
Insert ,
Loading history...
87
    });
88
89
    const bikes = createBicycleDto.map((bike) => {
90
      return this.bicycleRepository.create({
91
        batteryLevel: bike.batteryLevel ?? 100,
92
        latitude: bike.latitude,
93
        longitude: bike.longitude,
94
        status: bike.status ?? 'Available',
95
        city:
96
          bike.city === 'Jönköping'
97
            ? Jönköping
98
            : bike.city === 'Karlshamn'
99
              ? Karlshamn
100
              : defaultCity,
101
      });
102
    });
103
104
    return await this.bicycleRepository.save(bikes);
105
  }
106
107
  async findById(id: string): Promise<Bicycle> {
108
    const bike = await this.bicycleRepository.findOne({
109
      where: { id },
110
      relations: {
111
        city: true,
112
      },
113
    });
114 1
    if (!bike) {
115
      throw new NotFoundException('Bike not found');
116
    }
117
    return bike;
118
  }
119
120
  async update(id: string, updateBicycleDto: UpdateBicycleDto): Promise<Bicycle> {
121
    const bike = await this.findById(id);
122
123
    return this.bicycleRepository.save({ ...bike, ...updateBicycleDto });
124
  }
125
126
  async findByCity(cityName: CityName): Promise<Bicycle[]> {
127
    const bikes = await this.bicycleRepository.find({
128
      where: {
129
        city: {
130
          name: cityName,
131
        },
132
      },
133
      relations: ['city'],
134
    });
135
136
    return bikes;
137
  }
138
  async findByLocation(lat: number, lon: number, radius: number): Promise<Bicycle[]> {
139
    const allBikes = await this.findAll();
140
    const filteredBikes = allBikes.filter((bike) => {
141
      return getDistance(bike.latitude, bike.longitude, lat, lon) <= radius;
142
    });
143
    return filteredBikes;
144
  }
145
  async findByCityAndLocation(
146
    city: any,
147
    lat: number,
148
    lon: number,
149
    radius: number,
150
  ): Promise<Bicycle[]> {
151 2
    const bikesInCity = await this.findByCity(city);
152 2
    const filteredBikes = bikesInCity.filter((bike) => {
153 1
      return getDistance(bike.latitude, bike.longitude, lat, lon) <= radius;
154
    });
155 2
    return filteredBikes;
156
  }
157
158
  private toBicycleResponse(bike: Bicycle): BicycleResponse {
159
    return {
160
      id: bike.id,
161
      batteryLevel: bike.batteryLevel,
162
      latitude: bike.latitude,
163
      longitude: bike.longitude,
164
      status: bike.status,
165
      city: bike.city?.name,
166
      createdAt: bike.createdAt,
167
      updatedAt: bike.updatedAt,
168
    };
169
  }
170
171
  toBicycleResponses(bikes: Bicycle[]): BicycleResponse[] {
172
    return bikes.map((bike) => this.toBicycleResponse(bike));
173
  }
174
}
175